<?php

class Cache
{

    protected $instance;

    public function __construct()
    {
        return $this->connection();
    }

    public function connection()
    {
        if (!$this->instance) {
            if (extension_loaded('redis') && class_exists('Redis')) {
                $this->instance = new \Redis();
            } else {
                throw new Exception('Redis server has gone away.');
            }
            $servers = $this->getRedisServers();
            if (!$servers) return false;
            foreach ($servers as $server) {
                $this->instance->connect($server['host'], $server['port']);
            }
            $this->instance->select(getConfig()->redis->selectDB);
            $this->instance->setOption(\Redis::OPT_READ_TIMEOUT, -1);
        }
        return $this->instance;
    }

    public function db($db_num = 0)
    {
        $this->instance->select($db_num);
        return $this->instance;
    }

    public function __destruct()
    {
        $this->instance->close();
    }

    public function __call($method, $args)
    {
        $args[0] = CACHE_KEY_PREFIX . $args[0];

        return call_user_func_array([$this->instance, $method], $args);
    }

    public function set($key, $value, $ttl = 900)
    {
        $key = CACHE_KEY_PREFIX . $key;
        if (is_array($value)) {
            $value = json_encode($value, JSON_UNESCAPED_UNICODE);
        }
        if ($ttl > 0) {
            return $this->instance->setEx($key, $ttl, $value);
        } else {
            return $this->instance->set($key, $value);
        }
    }

    public function get($key)
    {
        $key = CACHE_KEY_PREFIX . $key;

        $result = json_decode($this->instance->get($key), TRUE);
        if ($result) {
            return $result;
        } else {
            return $this->instance->get($key);
        }
    }

    public function incr($key)
    {
        $key = CACHE_KEY_PREFIX . $key;

        return $this->instance->incr($key);
    }

    public function expire($key, $ttl = 900)
    {
        $key = CACHE_KEY_PREFIX . $key;

        return $this->instance->expire($key, $ttl);
    }

    public function exists($key)
    {
        $key = CACHE_KEY_PREFIX . $key;

        return $this->instance->exists($key);
    }

    public function delete($key)
    {
        $key = CACHE_KEY_PREFIX . $key;

        return $this->instance->delete($key);
    }

    public function lpush($key, $value)
    {
        $key = CACHE_KEY_PREFIX . $key;

        return $this->instance->lpush($key, $value);
    }

    public function llen($key)
    {
        $key = CACHE_KEY_PREFIX . $key;

        return $this->instance->llen($key);
    }

    public function rpop($key)
    {
        $key = CACHE_KEY_PREFIX . $key;

        return $this->instance->rpop($key);
    }

    public function sadd($key, $value)
    {
        $key = CACHE_KEY_PREFIX . $key;

        return $this->instance->sadd($key, $value);
    }

    public function smembers($key)
    {
        $key = CACHE_KEY_PREFIX . $key;

        return $this->instance->smembers($key);
    }

    public function srandmember($key)
    {
        $key = CACHE_KEY_PREFIX . $key;

        return $this->instance->srandmember($key);
    }

    public function flushdb()
    {
        return $this->instance->flushdb();
    }

    public function close()
    {
        return $this->instance->close();
    }

    public function getRedisServers()
    {
        $servers     = [];
        $rediscaches = getConfig()->redis;
        if (!empty($rediscaches)) {
            $hosts = explode('|', $rediscaches->hosts);
            $ports = explode('|', $rediscaches->ports);
            foreach ($hosts as $key => $host) {
                if (isset($ports[$key])) {
                    $servers[] = ['host' => $host, 'port' => $ports[$key]];
                }
            }
        }
        return $servers;
    }
}
